<!--
 * @author: wyf
 * @Date: 2022-06-13
 * @LastEditors: jixuanyu
 * @Description: 表单页面
-->
<template>
  <div class="form-preview">
    <z-form
      ref="ruleForm"
      :model="formModel"
      :rules="ruleList"
      autocomplete="off"
    >
      <z-row wrap :gutter="20">
        <!-- eslint-disable-next-line vue/no-v-for-template-key -->
        <template v-for="item in formList" :key="item.basicProperty.currentKey">
          <z-col
            v-if="item.basicProperty.attrType !== 'button' && item.basicProperty.attrType !== 'divider'"
            v-show="item.basicProperty.isShow == '1'"
            :span="item.formProperty.layoutVO.span"
            :offset="item.formProperty.layoutVO.offset"
            :pull="item.formProperty.layoutVO.pull"
            :push="item.formProperty.layoutVO.push"
            :xs="item.formProperty.layoutVO.xs"
            :sm="item.formProperty.layoutVO.sm"
            :md="item.formProperty.layoutVO.md"
            :lg="item.formProperty.layoutVO.lg"
            :xl="item.formProperty.layoutVO.xl"
            :xxl="item.formProperty.layoutVO.xxl"
            :xxxl="item.formProperty.layoutVO.xxxl"
          >
            <slot v-if="$slots[item.basicProperty.field]" :name="item.basicProperty.field" :formModel="formModel" />
            <component
              :is="formRender(item)"
              v-else
              ref="formRef"
              :form-model="formModel"
              :form-list="formList"
              :basic-property="item.basicProperty"
              :form-property="item.formProperty"
              @resetForm="resetForm"
              @validate="validate"
            />
          </z-col>
          <z-col
            v-else-if="item.basicProperty.attrType == 'button' || item.basicProperty.attrType == 'divider'"
            :span="24"
          >
            <component
              :is="formRender(item)"
              ref="formRef"
              :form-model="formModel"
              :form-list="formList"
              :basic-property="item.basicProperty"
              :form-property="item.formProperty"
              @resetForm="resetForm"
              @validate="validate"
            />
          </z-col>
        </template>
      </z-row>
    </z-form>
  </div>
</template>
<script>
import { defineComponent, reactive, ref, onMounted, computed } from 'vue'
import InputItem from './components/input.vue'
import Textarea from './components/textarea.vue'
import InputNumber from './components/input-number.vue'
import SelectItem from './components/select.vue'
import SwitchItem from './components/switch.vue'
import RateItem from './components/rate.vue'
import RadioItem from './components/radio.vue'
import CheckboxItem from './components/checkbox.vue'
import DateItem from './components/date.vue'
// import TimeItem from './components/time.vue'
// import DateTimeItem from './components/dateTime.vue'
import TreeItem from './components/tree.vue'
import TreeSelectItem from './components/treeSelect.vue'
import ButtonItem from './components/button.vue'
import DividerItem from './components/divider.vue'

import { message } from '../index.js'
import formInfo from '../../api/renderForm/index.js'
import { useStore } from 'vuex'

export default defineComponent({
  name: 'ZFormTemplate',
  components: {
    InputItem,
    Textarea,
    InputNumber,
    SelectItem,
    SwitchItem,
    RateItem,
    RadioItem,
    CheckboxItem,
    DateItem,
    // TimeItem,
    // DateTimeItem
    TreeItem,
    TreeSelectItem,
    ButtonItem,
    DividerItem
  },
  props: {
    formKey: {
      type: String,
      default: undefined
    },
    dataId: {
      type: String,
      default: undefined
    },
    // 点击提交的前置钩子函数
    beforeSubmit: {
      type: [Boolean, Function, Object],
      default: undefined
    },
    // 是否调用默认详情接口
    isGetDetail: {
      type: Boolean,
      default: true
    },
    // 用户传入自定义表单数据对象
    formData: {
      type: Object,
      default: undefined
    }
  },
  setup(props, context) {
    const store = useStore()

    let formList = ref([])
    let relaFormType = ref('')

    // 判断是否为JSON
    const IsJsonString = (str) => {
      try {
        JSON.parse(str)
      } catch (e) {
        return false
      }
      return true
    }
    // 表单组件详情
    const getFormDetail = () => {
      let params = {
        appId: 'ZRAR',
        formKey: props.formKey
      }
      formInfo.getFormKeyMessage(params).then((res) => {
        if (res.code === 1) {
          if (res?.data?.assBaseTableVOList) {
            formList.value = res.data.assBaseTableVOList.map((item) => {
              for (let [key, value] of Object.entries(item.baseVO)) {
                if (IsJsonString(value) && Array.isArray(JSON.parse(value)) === true) {
                  item.baseVO[key] = JSON.parse(value)
                }
              }
              for (let [key1, value1] of Object.entries(item.formAsseAttrVO)) {
                if (IsJsonString(value1) && Array.isArray(JSON.parse(value1)) === true) {
                  item.formAsseAttrVO[key1] = JSON.parse(value1)
                }
              }
              if (item.baseVO.attrType === 'rate') {
                item.formAsseAttrVO.value = Number(item.formAsseAttrVO.value)
              }
              return {
                basicProperty: item.baseVO,
                formProperty: item.formAsseAttrVO
              }
            })
          }

          // 按钮展示  --------- 处理比较复杂
          if (res.data.btnVOList?.length > 0) {
            let newMap = new Map()
            let arr = res.data.btnVOList
            // 取出不同行的按钮
            arr.forEach(c => {
              if (newMap.has(c.index)) {
                let _arr = newMap.get(c.index)
                newMap.set(c.index, [..._arr, c])
              } else {
                newMap.set(c.index, [c])
              }
            })
            // 确定每一行按钮组件
            newMap.forEach(item => {
              formList.value.push({
                basicProperty: {
                  index: item[0].index,
                  attrType: item[0].attrType,
                  id: 14,
                  currentKey: item[0].currentKey,
                  itemName: '按钮'
                },
                formProperty: {
                  btnArrList: []
                }
              })
            })
            // 按钮组件展示
            newMap.forEach(item => {
              item.forEach(i => {
                formList.value.forEach(item1 => {
                  if (item1.basicProperty.index === i.index) {
                    item1.formProperty.btnArrList.push(
                      {
                        btnType: i.btnType,
                        invertColor: i.invertColor,
                        btnText: i.btnText,
                        event: i.event,
                        type: i.type
                      }
                    )
                  }
                })
              })
            })
          }

          // 分割线
          res.data.lineVOList.forEach(item => {
            formList.value.push({
              basicProperty: {
                isShow: item.isShow,
                index: item.index,
                attrType: item.attrType,
                id: 0,
                currentKey: item.currentKey,
                itemName: '分割线'
              },
              formProperty: {
                lineText: item.lineText,
                align: item.align,
                lineLength: item.lineLength,
                lineWidth: item.lineWidth,
                lineType: item.lineType
              }
            })
          })

          // 数组排序
          formList.value.sort((a, b) => a.basicProperty.index - b.basicProperty.index)

          // 组件   添加操作中的显隐存值---vuex
          let isShowArr = []
          formList.value.forEach(i => {
            if (i.formProperty?.relaFields?.length > 0 && i.formProperty?.relaFields?.filter(j => j.operateType === '3').length > 0) {
              isShowArr.push({
                field: i.basicProperty.field,
                relaFields: i.formProperty?.relaFields?.filter(j => j.operateType === '3')
              })
            }
          })
          store.commit('formMake/UPDATE_ISSHOWARR', isShowArr)

          // 表单类型  -------  `详情` or `编辑`  要回显数据

          relaFormType.value = res.data.relaFormType
          if (res.data.relaFormType === '2' || res.data.relaFormType === '3') {
            if (relaFormType.value === '3') {
              formList.value.map(item => {
                for (let key in item.formProperty) {
                  if (key === 'disabled') {
                    item.formProperty[key] = '1'
                  }
                }
              })
            }
            if (props?.isGetDetail) {
              // 表单数据详情
              formInfo.getDataDetail({
                id: props.dataId,
                ...params
              }).then(res => {
                if (res.code === 1) {
                  for (let key1 in formModel.value) {
                    for (let key2 in res.data) {
                      if (key1 === key2) {
                        formModel.value[key1] = res.data[key2]
                      }
                    }
                  }
                }
              })
            }
          }
        }
      })
    }
    onMounted(() => {
      getFormDetail() // 获取组件详情
    })

    // 获取校验规则
    const getRuleList = () => {
      const lists = {}
      formList.value.forEach((list) => {
        const rules = []
        if (list.basicProperty.attrType === 'input' || list.basicProperty.attrType === 'number' || list.basicProperty.attrType === 'textarea') {
          rules.push({
            required: list.formProperty.required === '1',
            message: list.formProperty.placeHolder,
            trigger: 'blur'
          })
          // 数字输入框 max min 为最大最小值校验
          if (list.basicProperty.attrType === 'number') {
            if (list.formProperty.max && list.formProperty.max > 0) {
              rules.push({
                validator: async(_rule, value) => {
                  if (value === '') {
                    return Promise.resolve()
                  } else if (value > list.formProperty.max) {
                    return Promise.reject('不可大于' + list.formProperty.max)
                  } else {
                    return Promise.resolve()
                  }
                }
              })
            }
            if (list.formProperty.min && list.formProperty.min > 0) {
              rules.push({
                validator: async(_rule, value) => {
                  if (value === '') {
                    return Promise.reject('不可小于' + list.formProperty.min)
                  } else if (value < list.formProperty.min) {
                    return Promise.reject('不可小于' + list.formProperty.min)
                  } else {
                    return Promise.resolve()
                  }
                }
              })
            }
          } else {
            if (list.formProperty.max && list.formProperty.min) {
              rules.push({
                validator: async(_rule, value) => {
                  if (value === '' || value.length > list.formProperty.max || value.length < list.formProperty.min) {
                    return Promise.reject('请输入' + list.formProperty.min + '-' + list.formProperty.max + '位字符')
                  } else {
                    return Promise.resolve()
                  }
                }
              })
            } else if (list.formProperty.max && !list.formProperty.min) {
              rules.push({
                validator: async(_rule, value) => {
                  if (value === '') {
                    return Promise.resolve()
                  } else if (value.length > list.formProperty.max) {
                    return Promise.reject('长度不可大于' + list.formProperty.max)
                  } else {
                    return Promise.resolve()
                  }
                }
              })
            } else if (list.formProperty.min && !list.formProperty.max) {
              rules.push({
                validator: async(_rule, value) => {
                  if (value === '' || value.length < list.formProperty.min) {
                    return Promise.reject('长度不可小于' + list.formProperty.min)
                  } else {
                    return Promise.resolve()
                  }
                }
              })
            }
          }
        } else {
          rules.push({
            required: list.formProperty.required === '1',
            message: list.formProperty.placeHolder,
            trigger: 'change'
          })
        }

        if (
          list.formProperty.vaildRule &&
          list.formProperty.vaildRule.length > 0
        ) {
          list.formProperty.vaildRule.forEach((rule) => {
            rules.push({
              pattern: RegExp(rule),
              message: '格式不正确!',
              trigger: 'blur'
            })
          })
        }

        if (
          list.formProperty.customVaild &&
          list.formProperty.customVaild.length > 0
        ) {
          rules.push({
            // eslint-disable-next-line no-eval
            validator: eval(list.formProperty.customVaild)
          })
        }

        Object.assign(lists, {
          [list.basicProperty.field]: rules
        })
      })
      return lists
    }

    const ruleList = computed(() => reactive(getRuleList()))

    const ruleForm = ref(null)

    const formRef = ref(null)

    // 重置
    const resetForm = () => {
      formRef.value.forEach(item => {
        if (item.basicForm.attrType === 'select' || item.basicForm.attrType === 'checkbox' || item.basicForm.attrType === 'radio') {
          if (item.formForm.optionType === '1') {
            item.addOption = item.formForm.addOption
          } else {
            if (item.formForm.url) {
              formInfo.getRemoteData(item.formForm.url).then((res) => {
                if (res.code === 1) {
                  item.addOption = res.data.map(item1 => {
                    return {
                      label: item1[item.formForm.label],
                      value: item1[item.formForm.remoteValue],
                      disabled: false,
                      ...item1
                    }
                  })
                } else {
                  item.addOption = []
                }
              })
            }
          }
        }
      })
      ruleForm.value.resetFields()
      context.emit('resetForm')
    }

    // 获取组件数据对象
    const getFormModel = () => {
      const model = {}
      formList.value.forEach((list) => {
        if (list.basicProperty.attrType !== 'divider' && list.basicProperty.attrType !== 'button') {
          if (list.basicProperty.attrType === 'select') {
            Object.assign(model, {
              [list.basicProperty.field]: list.formProperty.value === '' || list.formProperty.value === null ? undefined : list.formProperty.value
            })
          } else if (list.basicProperty.attrType === 'checkbox') {
            Object.assign(model, {
              [list.basicProperty.field]: list.formProperty.value || []
            })
          } else if (list.basicProperty.attrType === 'treeSelect' && (list.formProperty.isShowCheckBox === '1' || list.formProperty.isMulCho === '1')) {
            Object.assign(model, {
              [list.basicProperty.field]: list.formProperty.value || []
            })
          } else {
            Object.assign(model, {
              [list.basicProperty.field]: list.formProperty.value || ''
            })
          }
        }
      })
      if (props?.formData) {
        Object.assign(model, props.formData)
      }
      return model
    }

    const formModel = computed(() => reactive(getFormModel()))

    // 组件渲染
    const formRender = (element) => {
      let componentId = 'InputItem'
      switch (element.basicProperty.attrType) {
        case 'input':
          componentId = 'InputItem'
          break
        case 'number':
          componentId = 'InputNumber'
          break
        case 'textarea':
          componentId = 'Textarea'
          break
        case 'select':
          componentId = 'SelectItem'
          break
        case 'switch':
          componentId = 'SwitchItem'
          break
        case 'rate':
          componentId = 'RateItem'
          break
        case 'radio':
          componentId = 'RadioItem'
          break
        case 'checkbox':
          componentId = 'CheckboxItem'
          break
        case 'date':
          componentId = 'DateItem'
          break
        // case 'time':
        //   componentId = 'TimeItem'
        //   break
        // case 'datetime':
        //   componentId = 'DateTimeItem'
        //   break
        case 'button':
          componentId = 'ButtonItem'
          break
        case 'divider':
          componentId = 'DividerItem'
          break
        case 'tree':
          componentId = 'TreeItem'
          break
        case 'treeSelect':
          componentId = 'TreeSelectItem'
          break
      }
      return componentId
    }

    // 提交
    const submitForm = () => {
      if (props.beforeSubmit === true) {
        return submit()
      }
      if (props.beforeSubmit === false) {
        return
      }
      const beforeSubmit = props.beforeSubmit(formModel.value)
      if (typeof beforeSubmit === 'boolean') {
        if (beforeSubmit) {
          return submit()
        }
      }
      if ((typeof beforeSubmit === 'object' || typeof beforeSubmit === 'function') && beforeSubmit && beforeSubmit.then) {
        beforeSubmit.then((form) => {
          submit(form)
        })
      }
    }

    // 提交
    const submit = (form) => {
      let dataAddVOList = []
      for (let [key, value] of Object.entries(formModel.value)) {
        dataAddVOList.push({
          attrName: key,
          value: value || ''
        })
      }
      let params = {
        appId: 'ZRAR',
        formKey: props.formKey,
        dataAddVOList: dataAddVOList
      }
      // 根据请求方式判断是新增还是编辑
      let method = ''
      if (relaFormType.value === '2') {
        params.pkValue = props.dataId
        // 编辑
        method = 'put'
      } else {
        // 新增
        method = 'post'
      }
      formInfo.changeFormInfo(form || params, method).then(res => {
        if (res.code === 1) {
          ruleForm.value.resetFields()
          message.success(res.message || res.data)
          context.emit('afterSubmit', form)
        }
      })
    }

    // 提交
    const validate = (nameList = []) => {
      return new Promise((resolve, reject) => {
        ruleForm.value.validate(nameList).then((res) => {
          submitForm()
          resolve(res)
        }).catch(error => {
          reject(error)
        })
      })
    }

    return {
      getFormDetail,
      ruleForm,
      resetForm,
      formList,
      relaFormType,
      formModel,
      ruleList,
      formRender,
      submitForm,
      validate,
      submit,
      formRef
    }
  }
})
</script>

<style lang="less">
.form-preview{
  padding-right: 10px;
  height: 100%;
  overflow: auto;
  .ant-form-item-label > label::after {
    content: "";
  }
}
</style>
